home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 04 - File Management / ScoresDemo / ScoresDemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-06  |  6.8 KB  |  277 lines  |  [TEXT/MMCC]

  1.  
  2. /* ScoresDemo */
  3.  
  4. /* by Ingemar Ragnemalm 1995 */
  5.  
  6. /* This demo shows how to save settings to a preference file, how to display
  7. a dialog asking for the player's name, and how to display a high score list */
  8.  
  9.  
  10. #include "MiniPreferences.h"
  11.  
  12.  
  13. #define abs(x) (x>0?x:-x)
  14.  
  15.  
  16. #define    kOKButton        1
  17. #define    kCancelButton    2
  18.  
  19.  
  20. /****************** A dialog asking for the player's name ******************/
  21.  
  22. /* StdFilter */
  23.  
  24. /* StdFilter is a dialog filter function that is useful for most
  25. modal dialogs, as long as they have an OK and a Cancel button.
  26. It maps return and enter to OK, and command-period and ESC to Cancel.
  27. It also draws a frame around the OK button. */
  28.  
  29. static pascal Boolean StdFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  30. {
  31.     char theChar;
  32.     short itemKind;
  33.     Handle itemHandle;
  34.     Rect itemBox;
  35.  
  36.     switch ( theEvent->what )
  37.         {
  38.         case keyDown: 
  39.                 theChar = (char)(theEvent->message & charCodeMask);
  40.                 if ( (((theEvent->modifiers & cmdKey) != 0) && (theChar == '.')) || (theChar == (char)27) ) /*cmd-. or ESC*/
  41.                     {
  42.                         *itemHit = kCancelButton;
  43. /*Highlight the cancel button*/
  44.                         GetDItem(theDialog, kCancelButton, &itemKind, &itemHandle, &itemBox);
  45.                         HiliteControl((ControlHandle)itemHandle, 1);
  46.  
  47.                         return true;
  48.                     };
  49.                 if ( (theChar == (char)13) || (theChar == (char)3) )
  50.                     {
  51.                         *itemHit = kOKButton;
  52. /*Highlight the OK button*/
  53.                         GetDItem(theDialog, 1, &itemKind, &itemHandle, &itemBox);
  54.                         HiliteControl((ControlHandle)itemHandle, kOKButton);
  55.  
  56.                         return true;
  57.                     };
  58.                 break; /*keyDown*/
  59.         case updateEvt:
  60.                 BeginUpdate(theDialog);
  61.                 SetPort(theDialog);
  62.  
  63.                 DrawDialog(theDialog);
  64.  
  65. /*Frame default button - item 1*/
  66.                 GetDItem(theDialog, kOKButton, &itemKind, &itemHandle, &itemBox);
  67.                 InsetRect(&itemBox, -4, -4);
  68.                 PenSize(3, 3);
  69.                 FrameRoundRect(&itemBox, 15, 15);
  70.  
  71.                 EndUpdate(theDialog);
  72.                 break; /*update event*/
  73.     }; /*case*/
  74.     return false;
  75. } /*StdFilter*/
  76.  
  77.  
  78. /* Copy a Pascal-string */
  79. static void CopyString(Str255 dest, Str255 src)
  80. {
  81.     short i;
  82.  
  83.     for (i=0; i <= src[0]; i++) dest[i] = src[i];
  84. } /* CopyString */
  85.  
  86.  
  87.  
  88. #define kHighDlogRes 128
  89.  
  90. /* Ask for players name (at highscore) */
  91. static void AskHigh(Str255 name)
  92. {
  93.     DialogPtr dialog;
  94.     GrafPtr oldPort;
  95.     short itemHit;
  96.     Handle itemHandle;
  97.     short itemType;
  98.     Rect itemRect;
  99.  
  100.     GetPort(&oldPort);
  101.     dialog = GetNewDialog(kHighDlogRes, nil, (WindowPtr)-1);
  102.     ShowWindow(dialog);
  103.     SelectWindow(dialog);
  104.     SetPort(dialog);
  105.  
  106.     GetDialogItem(dialog, 3, &itemType, &itemHandle, &itemRect);
  107.     SetDialogItemText(itemHandle, "\pYour name here");        /*Insert string from the prefs file here*/
  108.     SelectDialogItemText(dialog, 3, 0, 32767);
  109.     itemHit = -1;
  110.     while ( (itemHit != 1) && (itemHit != 2) ) /* 1=ok, 2=cancel */
  111.         ModalDialog(&StdFilter, &itemHit);
  112.     if ( itemHit == 2 )
  113.     {
  114.         name[0] = 0;    /* Empty string */
  115.     };
  116.     if ( itemHit == 1 )
  117.     {
  118.         GetDialogItem(dialog, 3, &itemType, &itemHandle, &itemRect);
  119.         GetDialogItemText(itemHandle, name);
  120.     };
  121.     SetPort(oldPort);
  122.     DisposeDialog(dialog);
  123. } /*AskHigh*/
  124.  
  125.  
  126. /****************** High score handling ******************/
  127.  
  128. #define kNameLength 15    /* Must match the length of the name string type */
  129.  
  130. static short gLastHigh;
  131.  
  132. /* Highscore record type */
  133.     
  134. typedef struct
  135. {
  136.     long score[11];
  137.     Str15 name[11];
  138. } HighScoreRec;
  139. typedef HighScoreRec **HighScoreHnd;
  140.  
  141. /* Global handle to the high score resource */
  142. HighScoreHnd gHighScoreHandle;
  143.  
  144. /* Call this on game over! */
  145. static void UpdateHighScore(long score)
  146. {
  147.     short rank;
  148.     Str255 name;
  149.  
  150.     if ( score > (**gHighScoreHandle).score[10] )
  151.     {
  152.         rank = 10;
  153. /*Call some function that asks for the name.*/
  154.         AskHigh(name);
  155. /*Max kNameLength characters! We take some extra trouble to append '…' too.*/
  156.         if ( name[0] > kNameLength )
  157.             name[0] = kNameLength;
  158.         if ( name[0] == 0 )        /* length of name = 0 */
  159.             return;
  160. /*Decrement rank until we get to a position where the one above is better!*/
  161.         while ( ((**gHighScoreHandle).score[rank - 1] < score) && (rank > 1) )
  162.             {
  163.                 (**gHighScoreHandle).score[rank] = gHighScoreHandle[0]->score[rank - 1];
  164.                 CopyString( (**gHighScoreHandle).name[rank] , gHighScoreHandle[0]->name[rank - 1]);
  165.                 rank--;
  166.             };
  167. /*Remember last high for the highscore display*/
  168.         gLastHigh = rank;
  169. /*Write in the score in the proper place and save*/
  170.         (**gHighScoreHandle).score[rank] = score;
  171.         CopyString( (**gHighScoreHandle).name[rank] , name);
  172.         ChangedResource((Handle)gHighScoreHandle);
  173.     }
  174. } /*UpdateHighScore*/
  175.  
  176.  
  177. /*InitScores*/
  178. /*This procedure loads the high score list from a resource in the current resource file,*/
  179. /*creating a new one if there is none.*/
  180.  
  181. static void InitScores()
  182. {
  183.     short rank;
  184.  
  185.     gHighScoreHandle = (HighScoreHnd)GetResource('Bäst', 0);
  186.     if ( gHighScoreHandle == nil )         /*Didn't exist - create it!*/
  187.     {
  188.         gHighScoreHandle = (HighScoreHnd)NewHandle(sizeof(HighScoreRec));
  189.         if ( gHighScoreHandle == nil )
  190.             ExitToShell();                /*Insert error message here*/
  191.         for ( rank = 1 ; rank < 10; rank++ )
  192.         {
  193.             (**gHighScoreHandle).score[rank] = 0;
  194.             CopyString( (**gHighScoreHandle).name[rank] , "\pNobody");
  195.         };
  196.         AddResource((Handle)gHighScoreHandle, 'Bäst', 0, "\pHigh scores");
  197.     }
  198.     else /*Did exist - check the size!*/
  199.         if ( GetHandleSize((Handle)gHighScoreHandle) < sizeof(HighScoreRec) )
  200.             SetHandleSize((Handle)gHighScoreHandle, sizeof(HighScoreRec));
  201. } /*InitScores*/
  202.  
  203.  
  204. /* Standard inits */
  205.  
  206. static void InitToolbox(void) {
  207.     InitGraf (&qd.thePort);
  208.     InitFonts ();
  209.     FlushEvents (everyEvent,0);
  210.     InitWindows ();
  211.     InitMenus ();
  212.     TEInit ();
  213.     InitDialogs (nil);
  214.     InitCursor ();
  215. }
  216.  
  217. /****************** Main program ******************/
  218.  
  219. void main(void) {
  220.     WindowPtr myWindow;
  221.     Str255 tempString;
  222.     Rect windowRectangle;
  223.     short score, rank;
  224.     short appFile, prefFile;
  225.  
  226.     InitToolbox();
  227.  
  228. /*Get the prefs file - create as necessary.*/
  229.     if ( SetPrefFile("\pScoresDemo Preferences", '????', 'pref', &appFile, &prefFile) )
  230.         ;
  231.  
  232. /*Set the current resource file to the preference file before InitScores*/
  233.     if ( prefFile != 0 )
  234.         UseResFile(prefFile);
  235.     InitScores();
  236.     UseResFile(appFile);
  237.  
  238. /*Let's seed the random number generator so we don't get the same all the time!*/
  239.     qd.randSeed = TickCount ();
  240.  
  241. /*Update the high score list with a random score.*/
  242.     score = Random();
  243.     UpdateHighScore(abs(score));
  244.  
  245. /*Set up the window*/
  246.     SetRect(&windowRectangle, 100, 100, 400, 260);
  247.     myWindow = NewCWindow(nil, &windowRectangle, "\pHigh scores demo", true, 0, (WindowPtr)-1L, false, 0);
  248.     SetPort(myWindow);
  249.  
  250.     for ( rank = 1 ; rank < 10; rank++)
  251.     {
  252.  
  253. /*We draw the latest high score with red.*/
  254.         if ( rank == gLastHigh )
  255.             ForeColor(redColor);
  256.         else
  257.             ForeColor(blackColor);
  258.  
  259. /*Draw the position number*/
  260.         MoveTo(10, 15 * rank);
  261.         NumToString(rank, tempString);
  262.         DrawString(tempString);
  263.  
  264. /*Draw the name*/
  265.         MoveTo(50, 15 * rank);
  266.         DrawString((**gHighScoreHandle).name[rank]);
  267.  
  268. /*Draw the score*/
  269.         MoveTo(200, 15 * rank);
  270.         NumToString((**gHighScoreHandle).score[rank], tempString);
  271.         DrawString(tempString);
  272.     };
  273.  
  274.     while ( ! Button () )
  275.         ;
  276. } /*ScoresDemo*/
  277.